﻿using jvm.rtda.heap.clazz.method;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace jvm.rtda.heap.clazz.cp
{
    class MethodDescriptorParser
    {
        public string src;
        public int offset;
        public MethodDescriptor parsed = new MethodDescriptor();

        public MethodDescriptorParser(string descriptor)
        {
            src = descriptor;
        }

        public char ReadChar()
        {
            char c = src[offset];
            offset++;
            return c;
        }

        public void UnRead()
        {
            offset--;
        }

        void CausePanic()
        {
            Console.WriteLine("Bad descriptor {0}", src);
            for (; ; );
        }

        public MethodDescriptor Parse()
        {
            StartParams();
            ParseParamTypes();
            EndParams();
            ParseReturnType();
            Finish();
            return parsed;
        }

        void StartParams()
        {
            if (ReadChar() != '(')
            {
                CausePanic();
            }
        }

        void EndParams()
        {
            if (ReadChar() != ')')
            {
                CausePanic();
            }
        }

        void Finish()
        {
            if (offset != src.Length)
            {
                CausePanic();
            }
        }

        void ParseParamTypes()
        {
            for (; ; )
            {
                string t = ParseFieldType();
                if (t.Equals(""))
                {
                    break;
                }
                parsed.paramTypes.Add(t);
            }
        }

        void ParseReturnType()
        {
            if (ReadChar() == 'V') {
                parsed.retType = "V";
                return;
            }

            UnRead();
            string t = ParseFieldType();
            if (!t.Equals(""))
            {
                parsed.retType = t;
                return;
            }
            CausePanic();
        }

        string ParseFieldType()
        {
            switch (ReadChar())
            {
                case 'B':
                    return "B";
                case 'C':
                    return "C";
                case 'D':
                    return "D";
                case 'F':
                    return "F";
                case 'I':
                    return "I";
                case 'J':
                    return "J";
                case 'S':
                    return "S";
                case 'Z':
                    return "Z";
                case 'L':
                    return ParseObjectType();
                case '[':
                    return ParseArrayType();
                default:
                    UnRead();
                    return "";
            }
        }

        string ParseObjectType()
        {
            int index = src.IndexOf(';', offset);
            if (index == -1)
            {
                CausePanic();
                return "";
            }
            int startIndex = offset - 1;
            offset = index + 1;
            int length = offset - startIndex;

            return src.Substring(startIndex, length);
        }

        string ParseArrayType()
        {
            int startIndex = offset - 1;
            ParseFieldType();
            return src.Substring(startIndex, offset - startIndex);
        }
    }
}
